import qs from 'qs'
import axios from 'axios'
import router from "@/router";
import {nextTick} from "vue";
import {ElMessage} from "element-plus";
import util from "./util";

export const http = axios.create({
    timeout: 2 * 60 * 1000,
    headers: {'X-Requested-With': 'XMLHttpRequest'},
    withCredentials: true,
    transformRequest: [data => qs.stringify(data)],  // for POST, PUT, PATCH requests
    paramsSerializer: qs.stringify                   // for GET request
})

function errorResp(err) {
    if (err.response.status === 401) {
        return router.push("/login");
    } else if (err.response.status === 403) {
        return router.push("/403");
    }
    ElMessage({
        type: "error",
        message: err.toJSON().message,
    });
    return Promise.reject('error');
}

function errorCreate(msg) {
    msg = util.isNull(msg) ? '系统异常' : msg;
    ElMessage({
        type: "error",
        message: msg,
    });
    throw new Error(msg);
}

export const contextPah = ""
http.interceptors.request.use(function (config) {
    config.url = contextPah + config.url
    return config
})

http.interceptors.response.use(response => {
    const dataAxios = response.data;
    // 这个状态码是和后端约定的
    const {code} = dataAxios;
    // 根据 code 进行判断
    if (code === undefined) {
        //文件下载
        if (response.config.responseType === 'blob') {
            return response;
        }
        // 如果没有 code 代表这不是项目后端开发的接口
        return response;
    } else {
        // 有 code 代表这是一个后端接口 可以进行进一步的判断
        switch (code) {
            case 0:
                // [ 示例 ] code === 0 代表没有错误
                return dataAxios;
            case -1:
                // [ 示例 ] 其它和后台约定的 code
                errorCreate(response.data.msg)
                break;
            default:
                // 不是正确的 code
                errorCreate(response.data.msg)
                break;
        }
    }
}, err => errorResp(err));

export function resource(path, service, actions) {
    let defaultActions = {
        get: id => service.get(path + "/" + id),
        getOne: params => service.get(path + "/one", {
            params
        }),
        list: params => service.get(path + "/list", {params}),
        listByIds: idArray => service.get(path + "/listByIds", {
            params: {
                items: idArray
            }
        }),
        count: searchCriteria => jsonRequest(path + '/count', "post", searchCriteria),
        exists: (rule, value, extParams = {}) => {
            let p = {}
            p[rule.field] = value
            let params = {...p, ...extParams}
            return service.get(path + "/validate", {params})
        },
        search: (table, reqCriteria) => searchRequest(table, reqCriteria, path + "/search"),
        del: id => service.delete(path + "/" + id),
        deleteBatch: idArray => service.delete(path, {
            params: {
                items: idArray
            }
        }),
        delByCond: cond => service.delete(path + '/cond', {
            params: cond
        }),
        deleteCriteria: searchCriteria => jsonRequest(path + '/deleteCriteria', "post", searchCriteria),
        add: obj => jsonRequest(path, "post", obj),
        addBatch: (objs) => {
            return jsonRequest(path + "/batch", 'post', objs)
        },
        modify: obj => jsonRequest(path, "put", obj),
        modifyBatch: (objs) => {
            return jsonRequest(path + "/batch", 'put', objs)
        },
        save: (obj, method) => {
            if (method !== "post" && method !== 'put') {
                throw new Error('保存只能够为post或put');
            }
            return jsonRequest(path, method, obj)
        },
        http: service,
    }

    return Object.assign(defaultActions, actions)
}

export const jsonRequest = function (path, method, data, responseType = 'json') {
    return http[method](path, data, {
        headers: {'Content-Type': 'application/json'},
        transformRequest: [data => JSON.stringify(data)],
        responseType
    })
}

export const searchRequest = (table, reqCriteria, path) => {
    table.loading = true
    let params = Object.assign({}, reqCriteria, {
        page: table.pageNumber,
        rows: table.pageSize,
    })
    return new Promise((resolve, reject) => {
        jsonRequest(path, "post", params).then(resp => {
            let res = resp.data
            table.rows = res.rows
            table.total = res.total
            table.pageSize = res.pageSize
            table.pageNumber = res.pageNumber
            resolve(res)
            nextTick(() => {
                table.loading = false
            })
        }).catch((error) => {
            table.loading = false
            return Promise.reject(error)
        })
    })
}

export function downloadBlob(res) {
    if (res.status !== 201 || res.headers['content-type'] === 'application/json') {
        //将Blob 对象转换成字符串
        let reader = new FileReader();
        reader.readAsText(res.data, 'utf-8');
        reader.onload = function (e) {
            errorCreate(JSON.parse(reader.result).msg)
        }
        return
    }
    // 创建新的URL并指向File对象或者Blob对象的地址
    const blobURL = window.URL.createObjectURL(res.data)
    // 创建a标签，用于跳转至下载链接
    const tempLink = document.createElement('a')
    tempLink.style.display = 'none'
    tempLink.href = blobURL
    let fileName = "download.zip";
    try {
        fileName = decodeURIComponent(res.headers['content-disposition']).split(';')[2].split('=')[1].replace(/\"/g, "");
    } catch (e) {
    }
    tempLink.setAttribute('download', fileName)
    // 兼容：某些浏览器不支持HTML5的download属性
    if (typeof tempLink.download === 'undefined') {
        tempLink.setAttribute('target', '_blank')
    }
    // 挂载a标签
    document.body.appendChild(tempLink)
    tempLink.click()
    document.body.removeChild(tempLink)
    // 释放blob URL地址
    window.URL.revokeObjectURL(blobURL)
}


export const User = resource('/user', http, {
    login: (params) => http.post('/login', params),
    register: (obj) => jsonRequest('/register', 'post', obj),
    meiRegister: (obj) => jsonRequest('/mei/register', 'post', obj),
    logout: () => http.get('/logout'),
    registerCheckExists: (rule, value) => {
        let params = {}
        params[rule.field] = value
        return http.post("/exists", params)
    },
    avatar: (obj) => jsonRequest('/user/avatar', 'put', obj),
})

export const Department = resource('/department', http, {
    tree: params => http.get('/department/tree', {params}),
})

export const Permission = resource('/permission', http, {
    tree: params => http.get('/permission/tree', {params}),
    getDefaultPermissionGroup: () => http.get('/permission/defaultPermissionGroup'),
    listMenus: () => http.get("/permission/listMenus"),
    listMenuTree: () => http.get("/permission/listMenuTree"),
    save: (obj, method) => {
        if (method === "post") {
            return jsonRequest("/permission/group", "post", obj)
        } else if (method === "put") {
            return jsonRequest("/permission", "put", obj)
        } else {
            throw new Error('保存只能够为post或get');
        }
    },
})

export const Role = resource('/role', http, {
    rolePermission: roleName => http.get("/permission/rolePermission/" + roleName),
    updateRolePermissions: obj => jsonRequest('/permission/updateRolePermissions', "post", obj),
    userRole: username => http.get("/role/userRoles/" + username),
    saveUserRole: (username, roleIds) => jsonRequest('/role/userRoles', "post", {
        "username": username,
        "roleIds": roleIds
    }),
    setCurrentRole: roleName => http.get("/role/role/current/" + roleName),
    getCurrentRole: () => http.get("/role/role/current"),
})

export const Auth = resource('', http, {
    authorizationCheck: () => http.get("/authorization-check"),
})

export const Dict = resource('/dict', http, {
    delByCode: (code) => http.delete('/dict/cond', {"params": {"code": code}}),
    listByCode: (code) => http.get(`/dict/list/${code}`),
    updateWithAttribute: (obj) => jsonRequest('/dict/updateWithAttribute', 'post', obj),
})

export const FileMapping = resource('/filemapping', http, {
    tree: params => http.get('/filemapping/tree', {params}),
    parents: (id) => http.get('/filemapping/parents?parent=' + id), // 获取所有父文件夹
    uploadToken: () => http.get('/filemapping/upload/token'),
    getUrl: (key) => http.get(`/filemapping/getUrl/${key}`),
})